//
//  ChaosConnection.m
//  Connection
//
//  Created by Worker on 3/17/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "ChaosConnection.h"

#import "ChaosConnectionError.h"
#import "ChaosAgent.h"
#import "Constants.h"
#import <Cordova/UIDevice+Extensions.h>
#import "HashUtility.h"
#import "CJSONDeserializer.h"

@implementation ChaosConnection
@synthesize delegate = delegate_;
@synthesize request = request_;
@synthesize status = status_;

- (void)dealloc
{
//	NSLog(@"%@, %@", self, NSStringFromSelector(_cmd));
	
//	[delegate_ release];
//	delegate_ = nil;
	[request_ release];
	request_ = nil;
	responseData = nil;
	[response_ release];
	response_ = nil;
	[super dealloc];
}

- (void)connect
{
	NSAssert(self.request.delegate != nil, @"ConnectionDelegate of Request is nil");
	if (status_ == connectionStatusRunning || status_ == connectionStatusFinished)
	{
		return;
	}
	
	status_ = connectionStatusRunning;
//	NSLog(@"%@, %@", self, NSStringFromSelector(_cmd));
//	NSLog(@"%@", request_.connectionURLString);
	NSURL *url = [NSURL URLWithString:[request_.connectionURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
	self.delegate = self.request.delegate;
	NSMutableURLRequest *connRequest = [NSMutableURLRequest requestWithURL:url];
	[connRequest setHTTPShouldHandleCookies:NO];
	[connRequest setHTTPMethod:request_.httpMethod];
	[connRequest addValue:request_.contentType forHTTPHeaderField:CONNECTION_CONTENT_TYPE];
    [connRequest setAllHTTPHeaderFields:[request_ httpHeaderDic]];
    if (request_.connectionMessage)
	{
		[connRequest setHTTPBody:request_.connectionMessage];
	}
	
	NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:connRequest delegate:self startImmediately:YES];
	response_ = [[ChaosResponse alloc] init];
	if (request_.requestIdentifier) {
		response_.requestIdentifier = request_.requestIdentifier;
	}
	if (theConnection)
	{
		responseData = [[NSMutableData data] retain];
	}
	else
	{
		// Create connection failed.
		ChaosConnectionError *error = [[ChaosConnectionError alloc] initWithDomain:ERROR_DOMAIN code:ERROR_CONNECTION_CODE userInfo:nil];
		response_.error = error;
		[error release];
		if (delegate_ && [delegate_ respondsToSelector:@selector(response:)])
		{
			[delegate_ response:response_];
		}
	}
}

- (void)connectHSBC {
    NSAssert(self.request.delegate != nil, @"ConnectionDelegate of Request is nil");
    if (status_ == connectionStatusRunning || status_ == connectionStatusFinished)
    {
        return;
    }
    
    status_ = connectionStatusRunning;
    //	NSLog(@"%@, %@", self, NSStringFromSelector(_cmd));
    //	NSLog(@"%@", request_.connectionURLString);
    NSURL *url = [NSURL URLWithString:[request_.connectionURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    self.delegate = self.request.delegate;
    
    NSString *requestData = request_.connectionBody;
    NSString *urlpath = request_.connectionURLString;
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    if ([@"POST"isEqualToString:request_.httpMethod])
    {
        request = [[NSMutableURLRequest alloc]initWithURL:url
                                              cachePolicy:NSURLRequestReloadIgnoringCacheData
                                          timeoutInterval:request_.timeout];
        if (requestData != nil)
        {
            NSString *mi_log = [NSString stringWithFormat:@"&%@=%@&%@=%@", PLATFORM_KEY, PLATFORM, DEVICE_TYPE_KEY, [UIDevice isPad]?DEVICE_TYPE_TABLET:DEVICE_TYPE_MOBILE];
            requestData = [requestData stringByAppendingString:mi_log];
            DebugLog(@"requestData with MI log: %@", requestData);
            
            [request setHTTPBody:[requestData dataUsingEncoding:NSUTF8StringEncoding]];
            
            DebugLog(@"POST Body set requestData is %@.",requestData);
        }
        else
        {
            NSString *mi_log = [NSString stringWithFormat:@"&%@=%@&%@=%@", PLATFORM_KEY, PLATFORM, DEVICE_TYPE_KEY, [UIDevice isPad]?DEVICE_TYPE_TABLET:DEVICE_TYPE_MOBILE];
            requestData = [requestData stringByAppendingString:mi_log];
            DebugLog(@"requestData with MI log: %@", requestData);
            
            [request setHTTPBody:[requestData dataUsingEncoding:NSUTF8StringEncoding]];
            
            DebugLog(@"POST Body set requestData is nil.");
        }
        
        [request setHTTPMethod:request_.httpMethod];
        [request setTimeoutInterval:request_.timeout];
    }
    else
    {
        NSURL *url;
        
        if (requestData)
        {
            NSString *mi_log = [NSString stringWithFormat:@"&%@=%@&%@=%@", PLATFORM_KEY, PLATFORM, DEVICE_TYPE_KEY, [UIDevice isPad]?DEVICE_TYPE_TABLET:DEVICE_TYPE_MOBILE];
            requestData = [requestData stringByAppendingString:mi_log];
            DebugLog(@"requestData with MI log: %@", requestData);
            
            if( [urlpath rangeOfString:@"?"].location == NSNotFound )
            {
                url = [NSURL URLWithString:[urlpath stringByAppendingFormat:@"?%@",requestData]];
            }
            else
            {
                
                url = [NSURL URLWithString:[urlpath stringByAppendingFormat:@"&%@",requestData]];
            }
        }
        else
        {
            url = [NSURL URLWithString:urlpath];
        }
        
        request = [[NSMutableURLRequest alloc]initWithURL:url
                                              cachePolicy:NSURLRequestReloadIgnoringCacheData
                                          timeoutInterval:request_.timeout];
        [request setHTTPMethod:request_.httpMethod];
        
        // setup the time out
    }
    
    
    //-native app version header
    [request    setValue:[NSString stringWithFormat:NATIVE_APP_VERSION_HTTP_HEADER_VALUE,
                          [[NSBundle mainBundle] objectForInfoDictionaryKey:@"REGION"],
                          [[NSBundle mainBundle] objectForInfoDictionaryKey:@"ENTITY"],
                          [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]]
      forHTTPHeaderField:NATIVE_APP_VERSION_HTTP_HEADER_FIELD];
    
    DebugLog(@"NATIVE APP VERSION HEADER: %@",[NSString stringWithFormat:NATIVE_APP_VERSION_HTTP_HEADER_VALUE,
                                               [[NSBundle mainBundle] objectForInfoDictionaryKey:@"REGION"],
                                               [[NSBundle mainBundle] objectForInfoDictionaryKey:@"ENTITY"],
                                               [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]]);
    
    //-device model/type for MI
    [request      setValue:[NSString stringWithFormat:NATIVE_APP_DEVICE_TYPE_HTTP_HEADER_VALUE,
                            [[UIDevice currentDevice] model],
                            [[UIDevice currentDevice] systemVersion]]
        forHTTPHeaderField:NATIVE_APP_DEVICE_TYPE_HTTP_HEADER_FIELD];
    
    DebugLog(@"DEVICE TYPE HEADER: %@",[NSString stringWithFormat:NATIVE_APP_DEVICE_TYPE_HTTP_HEADER_VALUE,
                                        [[UIDevice currentDevice] model],
                                        [[UIDevice currentDevice] systemVersion]]);
    
    //-UDID for fraud logging
    //- lwi Hash the UDID
    //NSString *myDeviceID = [UIDevice currentDevice].uniqueIdentifier;
    NSString *myDeviceID = [[UIDevice currentDevice] uniqueAppInstanceIdentifier];
    NSString *hashedUDID = [HashUtility createSHA512Hash:myDeviceID];
    [request setValue:hashedUDID forHTTPHeaderField:NATIVE_APP_DEVICE_ID_HTTP_HEADER_FIELD];
    DebugLog(@"UDID HEADER: %@", myDeviceID);
    DebugLog(@"Hashed UDID HEADER: %@",hashedUDID);
    
    
    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
    response_ = [[ChaosResponse alloc] init];
    if (request_.requestIdentifier) {
        response_.requestIdentifier = request_.requestIdentifier;
    }
    if (theConnection)
    {
        responseData = [[NSMutableData data] retain];
    }
    else
    {
        // Create connection failed.
        ChaosConnectionError *error = [[ChaosConnectionError alloc] initWithDomain:ERROR_DOMAIN code:ERROR_CONNECTION_CODE userInfo:nil];
        response_.error = error;
        [error release];
        if (delegate_ && [delegate_ respondsToSelector:@selector(response:)])
        {
            [delegate_ response:response_];
        }
    }
}

- (void)connectHSBCJSON {
    NSAssert(self.request.delegate != nil, @"ConnectionDelegate of Request is nil");
    if (status_ == connectionStatusRunning || status_ == connectionStatusFinished)
    {
        return;
    }
    
    status_ = connectionStatusRunning;
    //	NSLog(@"%@, %@", self, NSStringFromSelector(_cmd));
    //	NSLog(@"%@", request_.connectionURLString);
    NSURL *url = [NSURL URLWithString:[request_.connectionURLString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    self.delegate = self.request.delegate;
    
    NSString *requestData = request_.connectionBody;
    NSString *urlpath = request_.connectionURLString;
    
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    BOOL hasRequestString = NO;
    NSMutableString *requestString = [[NSMutableString alloc]init];

    if (requestData !=nil)
    {
        DebugLog(@"requestData: %@",requestData);
        
        NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];

        
        NSError *error;

        NSDictionary *requestInfo= [[CJSONDeserializer deserializer] deserialize:requestData error:&error];;
        
        if (requestInfo !=nil)
        {
            DebugLog(@"requestInfo: %@",requestInfo);
            hasRequestString = YES;
            
            NSArray *params = [requestInfo allKeys];
            for (NSInteger index=0; index<[params count]; index++)
            {
                NSString *key   = [params objectAtIndex:index];
                NSString *value =  [requestInfo objectForKey:key];
                
                // only encode value
                NSString *paramValue = nil;
                
                if ([value isKindOfClass:[NSString class]])
                {
                    paramValue = [ChaosConnection encodeURL:value];
                }
                
                if (paramValue == nil)
                {
                    continue;
                }
                
                [requestString appendString:[NSString stringWithFormat:@"%@=%@",
                                             key,
                                             paramValue,nil]];
                
                if (index == ([params count]-1))
                {
                    //nothing add
                }
                else
                {
                    [requestString appendString:@"&"];
                }
            }
        }
        [pool release];
    }
    
    if ([@"POST"isEqualToString:request_.httpMethod])
    {
        request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:urlpath]
                                              cachePolicy:NSURLRequestReloadIgnoringCacheData
                                          timeoutInterval:request_.timeout];
        if (hasRequestString == YES)
        {
            NSData *postData = [requestString dataUsingEncoding:NSUTF8StringEncoding];
            NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];
            [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
            [request setHTTPBody:postData];
            
            DebugLog(@"POST Body set requestData is %@.",requestString);
        }
        else
        {
            DebugLog(@"POST Body set requestData is nil.");
        }
        
        [request setHTTPMethod:request_.httpMethod];
        [request setTimeoutInterval:request_.timeout];
    
    }
    else
    {
        NSURL *url;
        
        if (hasRequestString == YES)
        {
            if( [urlpath rangeOfString:@"?"].location == NSNotFound )
            {
                url = [NSURL URLWithString:[urlpath stringByAppendingFormat:@"?%@",requestString]];
            }
            else
            {
                
                url = [NSURL URLWithString:[urlpath stringByAppendingFormat:@"&%@",requestString]];
            }
            
            DebugLog(@"GET requestData is %@.",[url absoluteString]);
        }
        else
        {
            url = [NSURL URLWithString:urlpath];
        }
        
        request = [[NSMutableURLRequest alloc]initWithURL:url
                                              cachePolicy:NSURLRequestReloadIgnoringCacheData
                                          timeoutInterval:request_.timeout];
        [request setHTTPMethod:request_.httpMethod];
        
        // setup the time out
    }

    
    [request setValue:@"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
    
    //-native app version header
    [request    setValue:[NSString stringWithFormat:NATIVE_APP_VERSION_HTTP_HEADER_VALUE,
                          [[NSBundle mainBundle] objectForInfoDictionaryKey:@"REGION"],
                          [[NSBundle mainBundle] objectForInfoDictionaryKey:@"ENTITY"],
                          [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]]
      forHTTPHeaderField:NATIVE_APP_VERSION_HTTP_HEADER_FIELD];
    
    DebugLog(@"NATIVE APP VERSION HEADER: %@",[NSString stringWithFormat:NATIVE_APP_VERSION_HTTP_HEADER_VALUE,
                                               [[NSBundle mainBundle] objectForInfoDictionaryKey:@"REGION"],
                                               [[NSBundle mainBundle] objectForInfoDictionaryKey:@"ENTITY"],
                                               [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]]);
    
    //-device model/type for MI
    [request      setValue:[NSString stringWithFormat:NATIVE_APP_DEVICE_TYPE_HTTP_HEADER_VALUE,
                            [[UIDevice currentDevice] model],
                            [[UIDevice currentDevice] systemVersion]]
        forHTTPHeaderField:NATIVE_APP_DEVICE_TYPE_HTTP_HEADER_FIELD];
    
    DebugLog(@"DEVICE TYPE HEADER: %@",[NSString stringWithFormat:NATIVE_APP_DEVICE_TYPE_HTTP_HEADER_VALUE,
                                        [[UIDevice currentDevice] model],
                                        [[UIDevice currentDevice] systemVersion]]);
    
    //-UDID for fraud logging
    //- lwi Hash the UDID
    //NSString *myDeviceID = [UIDevice currentDevice].uniqueIdentifier;
    NSString *myDeviceID = [[UIDevice currentDevice ] uniqueAppInstanceIdentifier];
    NSString *hashedUDID = [HashUtility createSHA512Hash:myDeviceID];
    [request setValue:hashedUDID forHTTPHeaderField:NATIVE_APP_DEVICE_ID_HTTP_HEADER_FIELD];
    DebugLog(@"UDID HEADER: %@", myDeviceID);
    DebugLog(@"Hashed UDID HEADER: %@",hashedUDID);
    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
    response_ = [[ChaosResponse alloc] init];
    if (request_.requestIdentifier) {
        response_.requestIdentifier = request_.requestIdentifier;
    }
    if (theConnection)
    {
        responseData = [[NSMutableData data] retain];
    }
    else
    {
        // Create connection failed.
        ChaosConnectionError *error = [[ChaosConnectionError alloc] initWithDomain:ERROR_DOMAIN code:ERROR_CONNECTION_CODE userInfo:nil];
        response_.error = error;
        [error release];
        if (delegate_ && [delegate_ respondsToSelector:@selector(response:)])
        {
            [delegate_ response:response_];
        }
    }
}

#pragma mark -
#pragma mark NSURLConnectionDelegate

- (NSURLRequest *)connection:(NSURLConnection *)connection
             willSendRequest:(NSURLRequest *)request
            redirectResponse:(NSURLResponse *)response
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    
    NSLog(@"willSendRequest request  :%@", [request URL]);
    //DebugLog(@"request header  :%@", [request allHTTPHeaderFields]);
    
    if (response)
    {
        if ([response isKindOfClass:[NSHTTPURLResponse class]])
        {
            NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *)response;
            NSLog(@"redirectResponse status code:%d", [httpResp statusCode]);
        }
        
        NSLog(@"redirectResponse response:%@"   , [response URL]);
        
        // original request
        //NSMutableURLRequest *new_request = [[request mutableCopy] autorelease];
        //[new_request setURL: [request URL]];
        //return new_request;
    }
    
    return request;
}

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    NSLog(@"canAuthenticateAgainstProtectionSpace");
    
    BOOL canAuthenticateFlag = NO;
    
    // certificate checking
    canAuthenticateFlag =[protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
    
    return canAuthenticateFlag;}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    NSLog(@"didReceiveAuthenticationChallenge");
	if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        NSLog(@"AuthenticationChallenge %@",NSURLAuthenticationMethodServerTrust);
        
        BOOL needAlertBox = NO;
        
        if (needAlertBox)
        {

            
        }
        else
        {
            // to handle the Server Trust Authentication Challenge without alert box.
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
        }
    }
    else
    {
        DebugLog(@"continueWithoutCredentialForAuthenticationChallenge");
        [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
	//NSLog(@"%@", NSStringFromSelector(_cmd));
	NSLog(@"---------Get Response Size: %lld", [response expectedContentLength]);
	NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
	response_.httpStatusCode = [httpResponse statusCode];
	[responseData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
	//NSLog(@"%@", NSStringFromSelector(_cmd));
	[responseData appendData:data];
    if (delegate_ && [delegate_ respondsToSelector:@selector(receiveDataLength:identifer:)])
    {
        [delegate_ receiveDataLength:data.length/1024.0f identifer:self.request.requestIdentifier];
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
	//NSLog(@"%@", NSStringFromSelector(_cmd));
	NSLog(@"Error is %@", error);
	[responseData release];
	[connection release];
	if (delegate_ && [delegate_ respondsToSelector:@selector(response:)])
	{
		response_.error = error;
		[delegate_ response:response_];
	}
	status_ = connectionStatusFinished;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
	NSLog(@"%@", NSStringFromSelector(_cmd));
	status_ = connectionStatusFinished;
//	[connection release];	
	if (delegate_ && [delegate_ respondsToSelector:@selector(response:)]) {
		response_.error = nil;
		response_.responseData = responseData;
		NSUInteger len = [responseData length];
		float kLen = (float)len / 1024.0f;
		NSLog(@"---------Get Response Size: %.2fK", kLen);
		[delegate_ response:response_];
	}	
	[[NSNotificationCenter defaultCenter] postNotificationName:CONNECTION_FINISHED_NOTIFICATION object:self];
}

+ (NSString*)encodeURL:(NSString *)string
{
    //  ASIFormDataRequest.m
    //  Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
    //  CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`")
    
    NSString *newString = [NSMakeCollectable(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                                                     (CFStringRef)string,
                                                                                     NULL,
                                                                                     CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"),
                                                                                     CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)))
                           autorelease];
    if (newString)
    {
        return newString;
    }
    return nil;
}

@end
